package com.egor.views.components;

import com.egor.data.entity.Department;
import com.egor.services.DepartmentService;
import com.egor.utils.ExcelGeneratorForDepartment;
import com.egor.views.components.modalboxes.EditDepartmentModalBox;
import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.button.ButtonVariant;
import com.vaadin.flow.component.grid.Grid;
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.component.textfield.TextField;
import com.vaadin.flow.data.provider.Query;
import com.vaadin.flow.data.value.ValueChangeMode;
import com.vaadin.flow.server.StreamResource;
import com.vaadin.flow.spring.annotation.RouteScope;
import com.vaadin.flow.spring.data.VaadinSpringDataHelpers;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Component;
import org.vaadin.olli.FileDownloadWrapper;

import java.util.List;

@Component
@RouteScope
public class DepartmentComponent extends VerticalLayout {
    private final HorizontalLayout toolbar = new HorizontalLayout();
    private final Grid<Department> grid = new Grid<>(Department.class);
    private final TextField filterText = new TextField();
    private final Button addButton = new Button("Add department");
    private final Button changeButton = new Button("Change department");
    private final Button deleteButton = new Button("Delete department");

    private final DepartmentService departmentService;
    private final EditDepartmentModalBox editDepartment;

    public DepartmentComponent(DepartmentService departmentService,
                               EditDepartmentModalBox editDepartment) {
        this.departmentService = departmentService;
        this.editDepartment = editDepartment;

        addClassName("departments-view");
        setSizeFull();
        setGrid();
        setToolbar();
        setModalBox();

        add(toolbar, grid);
    }

    private void setToolbar() {
        setButtons();
        setFilterText();

        toolbar.setWidthFull();
        toolbar.add(addButton, changeButton,
                deleteButton, gridExcelDownload(),
                gridPdfDownload(), filterText);
    }

    private void setGrid() {
        grid.setColumns("name", "description",
                        "dateOfOpen");

        grid.setItems(query -> departmentService.listAll(
                        PageRequest.of(query.getPage(), query.getPageSize(), VaadinSpringDataHelpers.toSpringDataSort(query)))
                .stream());

        grid.asSingleSelect().addValueChangeListener(event ->
                editDepartment.setDepartment(event.getValue()));
    }

    private void setButtons() {
        addButton.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
        deleteButton.addThemeVariants(ButtonVariant.LUMO_ERROR);

        addButton.addClickListener(event -> addDepartment());
        changeButton.addClickListener(event -> editDepartment());
        deleteButton.addClickListener(event -> deleteDepartment());
    }

    private void setFilterText() {
        filterText.setPlaceholder("Search...");
        filterText.setClearButtonVisible(true);
        filterText.setValueChangeMode(ValueChangeMode.LAZY);
        filterText.addValueChangeListener(e -> updateList());
    }

    private FileDownloadWrapper gridExcelDownload() {
        List<Department> departments = grid.getDataProvider().fetch(new Query<>()).toList();
        ExcelGeneratorForDepartment excelGeneratorForDepartment = new ExcelGeneratorForDepartment(departments);
        FileDownloadWrapper fileDownloadWrapper = new FileDownloadWrapper(new StreamResource("departments.xlsx",
                excelGeneratorForDepartment::generateExcelFile));

        Button button = new Button("Download Excel");
        fileDownloadWrapper.wrapComponent(button);
        return fileDownloadWrapper;
    }

    private FileDownloadWrapper gridPdfDownload() {
        List<Department> departments = grid.getDataProvider().fetch(new Query<>()).toList();
        ExcelGeneratorForDepartment excelGeneratorForDepartment = new ExcelGeneratorForDepartment(departments);
        FileDownloadWrapper fileDownloadWrapper = new FileDownloadWrapper(new StreamResource("departments.pdf",
                excelGeneratorForDepartment::generatePdfFile));

        Button button = new Button("Download PDF");
        fileDownloadWrapper.wrapComponent(button);
        return fileDownloadWrapper;
    }

    private void saveDepartment(EditDepartmentModalBox.SaveEvent event) {
        departmentService.save(event.getDepartment());
        updateList();
        closeEditor();
    }

    private void deleteDepartment() {
        Department department = grid.asSingleSelect().getValue();

        if (department != null) {
            departmentService.delete(department);
            updateList();
        }
    }

    private void closeEditor() {
        editDepartment.setDepartment(null);
        editDepartment.close();
    }

    public void editDepartment() {
        editDepartment.open();
    }

    private void addDepartment() {
        grid.asSingleSelect().clear();
        editDepartment.setDepartment(new Department());
        editDepartment.open();
    }

    private void setModalBox() {
        editDepartment.addListener(EditDepartmentModalBox.SaveEvent.class, this::saveDepartment);
        editDepartment.addListener(EditDepartmentModalBox.CloseEvent.class, e -> closeEditor());
    }

    private void updateList() {
        grid.setItems(query -> departmentService.findAll(filterText.getValue(),
                PageRequest.of(query.getPage(), query.getPageSize(), VaadinSpringDataHelpers.toSpringDataSort(query)))
                .stream());
    }
}
